/**
 *
 */
package org.jim.server.command;

import cn.hutool.core.annotation.AnnotationUtil;
import cn.hutool.core.collection.CollUtil;
import com.huiyun.project.common.core.util.SpringUtils;
import lombok.extern.slf4j.Slf4j;
import org.jim.core.exception.ImException;
import org.jim.core.packets.pub.consts.Command;
import org.jim.server.processor.MultiProtocolCmdProcessor;
import org.jim.server.processor.ProtocolCmdProcessor;
import org.jim.server.processor.SingleProtocolCmdProcessor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;

/**
 * 版本: [1.0]
 * 功能说明: 命令执行管理器;
 *
 * @author : WChao 创建时间: 2017年7月17日 下午2:23:41
 */
@Slf4j
public class CommandManager {
    /**
     * 通用cmd处理命令
     */
    private static Map<Integer, AbstractCmdHandler> handlerMap = new HashMap<>();
    private static Logger LOG = LoggerFactory.getLogger(CommandManager.class);

    private CommandManager() {
    }


    public static void init() {
        try {
            //List<CommandConfiguration> configurations = CommandConfigurationFactory.parseConfiguration();
            List<CommandConfiguration> configurations = new ArrayList<>();
            Map<String, Object> cmdHandlerMap = SpringUtils.getApplicationContext().getBeansWithAnnotation(CommandHandler.class);
            CommandHandler anno;
            CommandConfiguration config;
            for (Object obj : cmdHandlerMap.values()) {
                if (obj instanceof CmdHandler) {
                    anno = AnnotationUtil.getAnnotation(obj.getClass(), CommandHandler.class);
                    config = new CommandConfiguration();
                    Command command = anno.cmd();
                    config.setCmd(command.getNumber());
                    config.setCmdHandler((CmdHandler) obj);
                    config.setCmdProcessorClasses(Arrays.asList(anno.cmdProcessorClasses()));
                    configurations.add(config);
                }
            }
            //增加handler的方法结束
            init(configurations);
        } catch (Exception e) {
            LOG.error(e.toString(), e);
        }
    }

    private static void init(List<CommandConfiguration> configurations) throws Exception {
        for (CommandConfiguration configuration : configurations) {
//            AbstractCmdHandler cmdHandler = ((Class<AbstractCmdHandler>) Class.forName(configuration.getCmdHandler())).newInstance();
            AbstractCmdHandler cmdHandler = (AbstractCmdHandler) configuration.getCmdHandler();
            //实现类直接new出来的,如果使用此参数,必须写上具体的实现类
//            List<String> cmdProcessors = configuration.getCmdProcessors();
//            if (!cmdProcessors.isEmpty()) {
//                for (String cmdProcessor : cmdProcessors) {
//                    Object cmdProcessorObj = Class.forName(cmdProcessor).newInstance();
//                    if (cmdProcessorObj instanceof MultiProtocolCmdProcessor) {
//                        cmdHandler.addMultiProtocolProcessor((MultiProtocolCmdProcessor) cmdProcessorObj);
//                    } else if (cmdProcessorObj instanceof SingleProtocolCmdProcessor) {
//                        cmdHandler.setSingleProcessor((SingleProtocolCmdProcessor) cmdProcessorObj);
//                    }
//                }
//            }
            //解析Processor的实现类 add by linjie
            List<Class> classList = configuration.getCmdProcessorClasses();
            if (CollUtil.isNotEmpty(classList)) {
                for (Class cmdProcessor : classList) {
                    try {
                        Map<String, ProtocolCmdProcessor> result = SpringUtils.getApplicationContext().getBeansOfType(cmdProcessor);
                        for (ProtocolCmdProcessor val : result.values()) {
                            if (val instanceof SingleProtocolCmdProcessor) {
                                cmdHandler.setSingleProcessor((SingleProtocolCmdProcessor) val);
                            } else if (val instanceof MultiProtocolCmdProcessor) {
                                cmdHandler.addMultiProtocolProcessor((MultiProtocolCmdProcessor) val);
                            }
                        }
                    } catch (Exception ex) {
                        log.error(ex.getMessage());
                    }
                }
            }
            //将command放到map集合中
            registerCommand(cmdHandler);
        }
    }

    public static AbstractCmdHandler registerCommand(AbstractCmdHandler imCommandHandler) throws Exception {
        if (imCommandHandler == null || imCommandHandler.command() == null) {
            return null;
        }
        int cmd_number = imCommandHandler.command().getNumber();
        if (Objects.isNull(Command.forNumber(cmd_number))) {
            throw new ImException("failed to register cmd handler, illegal cmd code:" + cmd_number + ",use Command.addAndGet () to add in the enumerated Command class!");
        }
        if (Objects.isNull(handlerMap.get(cmd_number))) {
            return handlerMap.put(cmd_number, imCommandHandler);
        } else {
            throw new ImException("cmd code:" + cmd_number + ",has been registered, please correct!");
        }
    }

    public static AbstractCmdHandler removeCommand(Command command) {
        if (command == null) {
            return null;
        }
        int cmd_value = command.getNumber();
        if (handlerMap.get(cmd_value) != null) {
            return handlerMap.remove(cmd_value);
        }
        return null;
    }

    public static <T> T getCommand(Command command, Class<T> clazz) {
        AbstractCmdHandler cmdHandler = getCommand(command);
        if (cmdHandler != null) {
            return (T) cmdHandler;
        }
        return null;
    }

    public static AbstractCmdHandler getCommand(Command command) {
        if (command == null) {
            return null;
        }
        return handlerMap.get(command.getNumber());
    }
}
